<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Begin Jekyll SEO tag v2.7.1 -->
<title>流水线处理 | 微光</title>
<meta name="generator" content="Jekyll v4.2.1">
<meta property="og:title" content="流水线处理">
<meta property="og:locale" content="en_US">
<meta name="description" content="请求/响应协议和 RTT">
<meta property="og:description" content="请求/响应协议和 RTT">
<link rel="canonical" href="/redis/feature/pipeline.html">
<meta property="og:url" content="/redis/feature/pipeline.html">
<meta property="og:site_name" content="微光">
<meta property="og:type" content="article">
<meta property="article:published_time" content="2022-01-18T01:52:04+08:00">
<meta name="twitter:card" content="summary">
<meta property="twitter:title" content="流水线处理">
<script type="application/ld+json">
{"description":"请求/响应协议和 RTT","url":"/redis/feature/pipeline.html","headline":"流水线处理","dateModified":"2022-01-18T01:52:04+08:00","datePublished":"2022-01-18T01:52:04+08:00","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"/redis/feature/pipeline.html"},"@context":"https://schema.org"}</script>
<!-- End Jekyll SEO tag -->
<link rel="stylesheet" href="/assets/css/normalize.css">
  <link rel="stylesheet" href="/assets/css/style.css">
<link type="application/atom+xml" rel="alternate" href="/feed.xml" title="微光">
</head>
<body>
<header class="site-header">

  <div class="wrapper">
<a class="site-title" rel="author" href="/">微光</a><nav class="site-nav">
        <input type="checkbox" id="nav-trigger" class="nav-trigger">
        <label for="nav-trigger">
          <span class="menu-icon">
            <svg viewbox="0 0 18 15" width="18px" height="15px">
              <path d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.032C17.335,0,18,0.665,18,1.484L18,1.484z M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.032C17.335,6.031,18,6.696,18,7.516L18,7.516z M18,13.516C18,14.335,17.335,15,16.516,15H1.484 C0.665,15,0,14.335,0,13.516l0,0c0-0.82,0.665-1.483,1.484-1.483h15.032C17.335,12.031,18,12.695,18,13.516L18,13.516z"></path>
            </svg>
          </span>
        </label>

        <div class="trigger">
<a class="page-link" href="/about/">About</a><a class="page-link" href="/doc/main">DocMain</a><a class="page-link" href="/sites.html">Sites</a>
</div>
      </nav>
</div>
</header>
<div class="x-collections-bar">
  <a href="/">Home</a>
  
    
      <a href="/algri/index">算法</a>
    
  
    
      <a href="/java/index">Java</a>
    
  
    
  
    
  
    
      <a href="/redis/index">Redis</a>
    
  
</div>

<div class="x-content-side-layout x-container">
  <div class="x-left">
    <h3>本文目录</h3>
    <ul id="toc" class="section-nav">
<li class="toc-entry toc-h2"><a href="#%E8%AF%B7%E6%B1%82%E5%93%8D%E5%BA%94%E5%8D%8F%E8%AE%AE%E5%92%8C-rtt">请求/响应协议和 RTT</a></li>
<li class="toc-entry toc-h2"><a href="#redis-%E6%B5%81%E6%B0%B4%E7%BA%BF%E5%A4%84%E7%90%86">Redis 流水线处理</a></li>
<li class="toc-entry toc-h2"><a href="#%E4%B8%8D%E5%8F%AA%E6%98%AF-rtt-%E7%9A%84%E9%97%AE%E9%A2%98">不只是 RTT 的问题</a></li>
<li class="toc-entry toc-h2"><a href="#%E4%B8%80%E4%B8%AA%E7%9C%9F%E5%AE%9E%E4%B8%96%E7%95%8C%E7%9A%84%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B">一个真实世界的代码示例</a></li>
<li class="toc-entry toc-h2"><a href="#pipelining-vs-%E8%84%9A%E6%9C%AC">Pipelining VS 脚本</a></li>
<li class="toc-entry toc-h2"><a href="#%E9%99%84%E5%BD%95%E4%B8%BA%E4%BD%95-busy-loops-%E5%9C%A8-loopback-interface-%E4%B8%8A%E4%B9%9F%E5%BE%88%E6%85%A2">附录：为何 busy loops 在 loopback interface 上也很慢？</a></li>
<li class="toc-entry toc-h2"><a href="#%E5%8F%82%E8%80%83">参考</a></li>
</ul>
  </div>
  <div class="x-content">
    <h1><strong>Redis - 流水线处理</strong></h1>
    <small>2022-01-18 01:52:04 +0800</small>
    
    <article class="x-article"><h2 id="请求响应协议和-rtt">
<a class="anchor" href="#%E8%AF%B7%E6%B1%82%E5%93%8D%E5%BA%94%E5%8D%8F%E8%AE%AE%E5%92%8C-rtt" aria-hidden="true"><span class="octicon octicon-link"></span></a>请求/响应协议和 RTT</h2>

<p>Redis 是一个 TCP 服务器，它使用<strong>客户端-服务器模型</strong>和<strong>请求/响应协议</strong>。</p>

<p>这意味着一个请求通常需要以下几步才能完成：</p>

<ul>
  <li>客户端向服务器发送一个请求，从 socket 中读取服务端的响应，通常还是以一种阻塞的方式。</li>
  <li>服务器处理请求，然后把响应发回客户端。</li>
</ul>

<p>比如我们有像下面这样的四个命令序列：</p>

<ul>
  <li>客户端：<code class="language-plaintext highlighter-rouge">INCR X</code>
</li>
  <li>服务器：<code class="language-plaintext highlighter-rouge">1</code>
</li>
  <li>客户端：<code class="language-plaintext highlighter-rouge">INCR X</code>
</li>
  <li>服务器：<code class="language-plaintext highlighter-rouge">2</code>
</li>
  <li>客户端：<code class="language-plaintext highlighter-rouge">INCR X</code>
</li>
  <li>服务器：<code class="language-plaintext highlighter-rouge">3</code>
</li>
  <li>客户端：<code class="language-plaintext highlighter-rouge">INCR X</code>
</li>
  <li>服务器：<code class="language-plaintext highlighter-rouge">4</code>
</li>
</ul>

<p>客户端服务器通过一个网络链路相连。这个链路可能很快（比如 loopback interface），或者很慢（互联网上两个主机之间有很多跳的连接）。不管网络延迟如何，数据包在客户端和服务器之间传输时总是要花时间的。</p>

<p>这个时间就被称为 RTT（Round Trip Time）。容易看出，当客户端需要连续执行一串请求时，RTT 会直接影响性能表现。比如，如果 RTT 时间是 250 毫秒（这算是互联网上的一个非常慢的链路了），如果服务器每秒能够处理 10 万个请求，那么这种情况下，，每秒最多只能处理 4 个请求。</p>

<p>如果链路使用 loopback interface，RTT 时间会非常短（通常不超过 0.1 毫秒），但是如果你需要顺序地执行写操作时，这个时间依然显得很多。</p>

<p>Redis 提供了一种方法来提升此种场景下的性能。</p>

<h2 id="redis-流水线处理">
<a class="anchor" href="#redis-%E6%B5%81%E6%B0%B4%E7%BA%BF%E5%A4%84%E7%90%86" aria-hidden="true"><span class="octicon octicon-link"></span></a>Redis 流水线处理</h2>

<p>一个请求/响应服务器可以这样实现，以使得即使在客户端还没有读取旧请求时也能发送新请求。这种方式能够发送多个命令到服务器而不用等待响应返回，最后用一个单独的步骤来读响应。</p>

<p>这叫流水线处理，这个技术已经被使用了很多年了。比如 POP3 协议就已经实现了这个特性，明显地提升了从服务器下载电子邮件的速度。</p>

<p>Redis 很早就支持了流水线处理了，所以不管你使用哪个版本，你都可以使用流水线。这是一个使用原始 netcat 工具的例子：</p>

<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span><span class="o">(</span><span class="nb">printf</span> <span class="s2">"PING</span><span class="se">\r\n</span><span class="s2">PING</span><span class="se">\r\n</span><span class="s2">PING</span><span class="se">\r\n</span><span class="s2">"</span><span class="p">;</span> <span class="nb">sleep </span>1<span class="o">)</span> | nc localhost 6379
<span class="go">+PONG
+PONG
+PONG
</span></code></pre></div></div>

<p>这样，我们就不用对每个请求都花费一次 RTT 时间了，三个命令只需要一个 RTT 时间。</p>

<p>我们把第一个例子中的命令改用流水线处理如下：</p>

<ul>
  <li>客户端：<code class="language-plaintext highlighter-rouge">INCR X</code>
</li>
  <li>客户端：<code class="language-plaintext highlighter-rouge">INCR X</code>
</li>
  <li>客户端：<code class="language-plaintext highlighter-rouge">INCR X</code>
</li>
  <li>客户端：<code class="language-plaintext highlighter-rouge">INCR X</code>
</li>
  <li>服务器：<code class="language-plaintext highlighter-rouge">1</code>
</li>
  <li>服务器：<code class="language-plaintext highlighter-rouge">2</code>
</li>
  <li>服务器：<code class="language-plaintext highlighter-rouge">3</code>
</li>
  <li>服务器：<code class="language-plaintext highlighter-rouge">4</code>
</li>
</ul>

<p><strong>注意：</strong>当客户端使用流水线发送命令时，服务器必须<em>在内存中</em>对响应进行排队。如果你需要以流水线方式发送了大量命令，最好对这些命令分批执行，每批次包含的命令数量要合理些，比如先发送 1 万个命令，等读到回复时，在发送另外 1 万个命令，如此反复。这样速度几乎一样，不过 Redis 使用的额外内存的最大数量就成了排队的 1 万个命令的返回。</p>

<h2 id="不只是-rtt-的问题">
<a class="anchor" href="#%E4%B8%8D%E5%8F%AA%E6%98%AF-rtt-%E7%9A%84%E9%97%AE%E9%A2%98" aria-hidden="true"><span class="octicon octicon-link"></span></a>不只是 RTT 的问题</h2>

<p>流水线不仅仅是一个减少 RTT 导致的时延的方式，它还能极大提升一个给定 Redis 服务器每秒能执行的操作数量。原因是，若不使用流水线，即使从访问数据和产生响应的角度看，处理每个命令都很廉价，但是从 socket I/O 的角度看，花费依然很大。这涉及到 <code class="language-plaintext highlighter-rouge">read(2)</code> 和 <code class="language-plaintext highlighter-rouge">write(2)</code> 系统调用，这意味着要在用户空间和内核空间进行上下文切换，而这回十分影响速度。</p>

<p>在使用流水线时，多个命令的读一般会使用一次 <code class="language-plaintext highlighter-rouge">read(2)</code> 系统调用，多个回复在发送时使用一个 <code class="language-plaintext highlighter-rouge">write(2)</code> 系统调用。因此，从下图中可以看出，开始的时候，Redis 每秒能处理查询总数随流水线长度线性增加，最终流水线方式的吞吐量稳定在不使用流水线的 10 倍左右。</p>

<p><img src="/assets/img/redis-pipeline-iops.png" alt=""></p>

<h2 id="一个真实世界的代码示例">
<a class="anchor" href="#%E4%B8%80%E4%B8%AA%E7%9C%9F%E5%AE%9E%E4%B8%96%E7%95%8C%E7%9A%84%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B" aria-hidden="true"><span class="octicon octicon-link"></span></a>一个真实世界的代码示例</h2>

<p>下面我们使用 NodeJS 的库 ioredis 来测试 pipelining 带来的速度提升：</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">Redis</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">ioredis</span><span class="dl">'</span><span class="p">)</span>
<span class="kd">const</span> <span class="nx">prettyHrtime</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">pretty-hrtime</span><span class="dl">'</span><span class="p">)</span>

<span class="kd">const</span> <span class="nx">redis</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Redis</span><span class="p">({</span> <span class="na">host</span><span class="p">:</span> <span class="dl">'</span><span class="s1">localhost</span><span class="dl">'</span><span class="p">,</span> <span class="na">port</span><span class="p">:</span> <span class="mi">6379</span> <span class="p">})</span>

<span class="kd">const</span> <span class="nx">COUNT</span> <span class="o">=</span> <span class="mi">100</span><span class="nx">_0000</span>

<span class="k">async</span> <span class="kd">function</span> <span class="nx">execInARow</span> <span class="p">()</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">key</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">demo:benchmark:exec-in-a-row</span><span class="dl">'</span>
  <span class="kd">const</span> <span class="nx">start</span> <span class="o">=</span> <span class="nx">process</span><span class="p">.</span><span class="nx">hrtime</span><span class="p">()</span>

  <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">COUNT</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">await</span> <span class="nx">redis</span><span class="p">.</span><span class="nx">incr</span><span class="p">(</span><span class="nx">key</span><span class="p">)</span>
  <span class="p">}</span>

  <span class="kd">const</span> <span class="nx">end</span> <span class="o">=</span> <span class="nx">process</span><span class="p">.</span><span class="nx">hrtime</span><span class="p">(</span><span class="nx">start</span><span class="p">)</span>
  <span class="kd">const</span> <span class="nx">result</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">redis</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="nx">key</span><span class="p">)</span>
  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">`挨个执行\t用时: </span><span class="p">${</span><span class="nx">prettyHrtime</span><span class="p">(</span><span class="nx">end</span><span class="p">)}</span><span class="s2">\t结果: </span><span class="p">${</span><span class="nx">result</span><span class="p">}</span><span class="s2">`</span><span class="p">)</span>
  <span class="k">await</span> <span class="nx">redis</span><span class="p">.</span><span class="nx">expire</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">async</span> <span class="kd">function</span> <span class="nx">execPipelining</span> <span class="p">(</span><span class="nx">batchSize</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">key</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">demo:benchmark:exec-pipelining:</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">batchSize</span>
  <span class="kd">const</span> <span class="nx">start</span> <span class="o">=</span> <span class="nx">process</span><span class="p">.</span><span class="nx">hrtime</span><span class="p">()</span>

  <span class="kd">let</span> <span class="nx">pipeline</span> <span class="o">=</span> <span class="nx">redis</span><span class="p">.</span><span class="nx">pipeline</span><span class="p">()</span>
  <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;=</span> <span class="nx">COUNT</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">pipeline</span><span class="p">.</span><span class="nx">incr</span><span class="p">(</span><span class="nx">key</span><span class="p">)</span>
    <span class="k">if</span> <span class="p">(</span><span class="nx">i</span> <span class="o">%</span> <span class="nx">batchSize</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">await</span> <span class="nx">pipeline</span><span class="p">.</span><span class="nx">exec</span><span class="p">()</span>
      <span class="nx">pipeline</span> <span class="o">=</span> <span class="nx">redis</span><span class="p">.</span><span class="nx">pipeline</span><span class="p">()</span>
    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">i</span> <span class="o">==</span> <span class="nx">COUNT</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">await</span> <span class="nx">pipeline</span><span class="p">.</span><span class="nx">exec</span><span class="p">()</span>
    <span class="p">}</span>
  <span class="p">}</span>

  <span class="kd">const</span> <span class="nx">end</span> <span class="o">=</span> <span class="nx">process</span><span class="p">.</span><span class="nx">hrtime</span><span class="p">(</span><span class="nx">start</span><span class="p">)</span>
  <span class="kd">const</span> <span class="nx">result</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">redis</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="nx">key</span><span class="p">)</span>
  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">`管道[</span><span class="p">${</span><span class="nx">batchSize</span><span class="p">}</span><span class="s2">]\t用时: </span><span class="p">${</span><span class="nx">prettyHrtime</span><span class="p">(</span><span class="nx">end</span><span class="p">)}</span><span class="s2">\t结果: </span><span class="p">${</span><span class="nx">result</span><span class="p">}</span><span class="s2">`</span><span class="p">)</span>
  <span class="k">await</span> <span class="nx">redis</span><span class="p">.</span><span class="nx">expire</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">async</span> <span class="kd">function</span> <span class="nx">app</span> <span class="p">()</span> <span class="p">{</span>
  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">开始</span><span class="dl">'</span><span class="p">)</span>
  <span class="k">await</span> <span class="nx">execInARow</span><span class="p">()</span>
  <span class="k">await</span> <span class="nx">execPipelining</span><span class="p">(</span><span class="mi">100</span><span class="p">)</span>
  <span class="k">await</span> <span class="nx">execPipelining</span><span class="p">(</span><span class="mi">1000</span><span class="p">)</span>
  <span class="k">await</span> <span class="nx">execPipelining</span><span class="p">(</span><span class="mi">10000</span><span class="p">)</span>
  <span class="k">await</span> <span class="nx">execPipelining</span><span class="p">(</span><span class="mi">30000</span><span class="p">)</span>
  <span class="k">await</span> <span class="nx">execPipelining</span><span class="p">(</span><span class="mi">50000</span><span class="p">)</span>
  <span class="k">await</span> <span class="nx">execPipelining</span><span class="p">(</span><span class="mi">100000</span><span class="p">)</span>
  <span class="k">await</span> <span class="nx">execPipelining</span><span class="p">(</span><span class="mi">1000000</span><span class="p">)</span>
<span class="p">}</span>

<span class="nx">app</span><span class="p">()</span>
  <span class="p">.</span><span class="nx">then</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="nx">process</span><span class="p">.</span><span class="nx">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">))</span>
  <span class="p">.</span><span class="k">catch</span><span class="p">(</span><span class="nx">err</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span>
    <span class="nx">process</span><span class="p">.</span><span class="nx">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
  <span class="p">})</span>
</code></pre></div></div>

<p>上面的简单代码在我的 Mac OS X 上，使用 loopback interface 以使得 RTT 非常低，某次执行得到以下结果：</p>

<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">开始
挨个执行        用时: 51 s      结果: 1000000
管道[100]       用时: 3.1 s     结果: 1000000
管道[1000]      用时: 2.21 s    结果: 1000000
管道[10000]     用时: 2.29 s    结果: 1000000
管道[30000]     用时: 2.64 s    结果: 1000000
管道[50000]     用时: 2.78 s    结果: 1000000
管道[100000]    用时: 3.04 s    结果: 1000000
管道[1000000]   用时: 4.18 s    结果: 1000000
</span></code></pre></div></div>

<p>可以看到，使用 pipelining，性能提升会有 10 倍以上的提升，但是 pipelining 的大小也是影响性能的因素，这就需要使用者做权衡了。</p>

<h2 id="pipelining-vs-脚本">
<a class="anchor" href="#pipelining-vs-%E8%84%9A%E6%9C%AC" aria-hidden="true"><span class="octicon octicon-link"></span></a>Pipelining VS 脚本</h2>

<p>使用 Redis 脚本（`自 2.6 版本起开始支持），很多使用 pipelining 来让服务器处理大量工作的场景，都可以更有效率地解决了。脚本的一大优点是它可以同时在读和写数据两方面最小化时延，使得像 <em>读</em>、<em>计算</em>、<em>写</em>之类的操作非常快。Pipelining 就做不到，因为客户端需在调用写命令之前，要先得到读命令的回复。</p>

<p>有时程序希望在 pipelining 中发送 <code class="language-plaintext highlighter-rouge">EVAL</code> 和 <code class="language-plaintext highlighter-rouge">EVALSHA</code> 命令。这是完全可行的，Redis 通过 <code class="language-plaintext highlighter-rouge">SCRIPT LOAD</code> 命令来支持（这保证了 <code class="language-plaintext highlighter-rouge">EVALSHA</code> 可以被调用，而没有失败的风险）。</p>

<h2 id="附录为何-busy-loops-在-loopback-interface-上也很慢">
<a class="anchor" href="#%E9%99%84%E5%BD%95%E4%B8%BA%E4%BD%95-busy-loops-%E5%9C%A8-loopback-interface-%E4%B8%8A%E4%B9%9F%E5%BE%88%E6%85%A2" aria-hidden="true"><span class="octicon octicon-link"></span></a>附录：为何 busy loops 在 loopback interface 上也很慢？</h2>

<p>尽管上面把该说的都说了，你可能还想知道为何 Redis 就像下面的那样（伪代码），即使在 loopback interface 环境执行且客户端和服务器同一个物理机器上跑也很慢：</p>

<pre><code class="language-basic">FOR-ONE-SECOND:
    Redis.SET("foo","bar")
END
</code></pre>

<p>毕竟，如果两个 Redis 进程和跑分在一起跑，不是仅仅把消息从内存中的一个地方复制到另一个地方就行，而没有任何的时延以及网络开销么？</p>

<p>原因是系统中的进程并不总是在跑，而是由内核调度其来调度进程在跑。所以，当允许跑分执行时，它从 Redis 服务器读取回复（来自最后执行的命令），然后写一个新命令。这个命令现在在 loopback interface buffer 中，不过为了使服务器可以读到，内核要调度服务器进程去执行，等等。所以在实践中，loopback interface 依然会有类似网络产生的时延，这是由内核调度器的工作方式决定的。</p>

<p>基本上，在测量网络服务器的性能时，繁忙循环基准测试是最愚蠢的做法。明智的做法是避免以这种方式进行基准测试。</p>

<h2 id="参考">
<a class="anchor" href="#%E5%8F%82%E8%80%83" aria-hidden="true"><span class="octicon octicon-link"></span></a>参考</h2>

<ul>
  <li><a href="https://redis.io/topics/pipelining">Using pipelining to speedup Redis queries</a></li>
</ul>
</article>
  </div>
  <div class="x-right">
    <h3>Redis</h3>
    
      <div class="x-collection-section">
        <h4>开始</h4>
        
        <ol>
          
            
              <li><a href="/redis/index.html">开始</a></li>
            
          
            
              <li><a href="/redis/install.html">安装</a></li>
            
          
            
              <li><a href="/redis/concept.html">相关概念预览</a></li>
            
          
        </ol>
      </div>
    
      <div class="x-collection-section">
        <h4>数据类型</h4>
        
        <ol>
          
            
              <li><a href="/redis/data-type/key-and-string.html">Key 和 String</a></li>
            
          
            
              <li><a href="/redis/data-type/list.html">List</a></li>
            
          
            
              <li><a href="/redis/data-type/hash.html">Hash</a></li>
            
          
            
              <li><a href="/redis/data-type/set.html">Set</a></li>
            
          
            
              <li><a href="/redis/data-type/zset.html">Sorted Set</a></li>
            
          
            
              <li><a href="/redis/data-type/bitmap.html">Bitmap</a></li>
            
          
            
              <li><a href="/redis/data-type/hyperloglog.html">Hyperloglog</a></li>
            
          
            
              <li><a href="/redis/data-type/geo.html">Geo</a></li>
            
          
        </ol>
      </div>
    
      <div class="x-collection-section">
        <h4>其他特性</h4>
        
        <ol>
          
            
              <li class="active"><a href="/redis/feature/pipeline.html">流水线处理</a></li>
            
          
        </ol>
      </div>
    
      <div class="x-collection-section">
        <h4>持久化</h4>
        
        <ol>
          
            
              <li><a href="/redis/persist/durability.html">持久化在说什么</a></li>
            
          
            
              <li><a href="/redis/persist/rdb.html">快照（Snapshotting）</a></li>
            
          
            
              <li><a href="/redis/persist/aof.html">AOF</a></li>
            
          
        </ol>
      </div>
    
      <div class="x-collection-section">
        <h4>运维</h4>
        
        <ol>
          
            
              <li><a href="/redis/ops/persistence.html">持久化方案</a></li>
            
          
        </ol>
      </div>
    
      <div class="x-collection-section">
        <h4>应用场景</h4>
        
        <ol>
          
            
              <li><a href="/redis/usecase/blogs.html">应用场景相关文章</a></li>
            
          
        </ol>
      </div>
    
  </div>
</div>
<footer class="site-footer h-card">
  <data class="u-url" href="/"></data>

  <div class="wrapper">

    <div class="footer-col-wrapper">
      <div class="footer-col">
        <p class="feed-subscribe">
          <a href="/feed.xml">
            <svg class="svg-icon orange">
              <use xlink:href="/assets/social-icons.svg#rss"></use>
            </svg><span>Subscribe</span>
          </a>
        </p>
      </div>
      <div class="footer-col">
        <p>Write an awesome description for your new site here. You can edit this line in _config.yml. It will appear in your document head meta (for Google search results) and in your feed.xml site description.</p>
      </div>
    </div>

    <div class="social-links"></div>

  </div>

</footer>
</body>
</html>
